from transitions import Machine, State
from concurrent.futures import ThreadPoolExecutor
from logger.logger import logger
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
from .tooltip import ToolTip


class StepManagerView(ttk.LabelFrame):
    def __init__(self, mainView=None, parentView=None, stepManager=None):
        self.parentView = parentView
        self.mainView = mainView
        if parentView is None:  # 用于测试时，没有parentView的情况
            parentView = mainView
        super().__init__(master=parentView, text='parent-view')
        self.pack()

        # 初始化StepManager
        self.initStepManager(stepManager)

        # 初始化StepBar组件，用于显示step名称，stepLabel_dict用于存储Label组件，key为step名称，value为Label组件
        self.stepBtn_dict: dict[str, tk.Button] = {}
        self.init_stepFrame()

        # 初始化Listbox组件
        self.init_logFrame()

    def initStepManager(self, stepManager):
        self.stepManager = stepManager
        self.stepManager.stepManagerView = self

        # 添加默认的on_enter方法，用于测试时，没有on_enter方法的情况
        self.stepManager.add_default_tostate()

        pass

    def init_stepFrame(self):  # 用于测试时，没有parentView的情况
        states = self.stepManager.States
        # logger.debug(f'states: {states}')  # 打印states，用于调试

        self.stepFrame = ttk.LabelFrame(self, text='step-bar')
        self.stepFrame.pack(side=tk.LEFT)
        # 遍历states，创建Label组件，用于显示step名称，stepLabel_dict用于存储Label组件，key为step名称，value为Label组件

        def create_closure(name):
            def wrapper():
                to_name = f'to_{name}'
                self.stepManager.trigger(to_name)
            return wrapper

        for i, state in enumerate(states):
            name = state.get('name')
            cur_stepBtn = tk.Button(
                self.stepFrame, text=name, command=create_closure(name))
            # 布局，row为行号，column为列号，padx为水平间距，pady为垂直间距
            cur_stepBtn.pack()

            # 添加tooltip提示
            ToolTip(cur_stepBtn, text=state.get('description', 'step00'))
            self.stepBtn_dict[name] = cur_stepBtn

    def init_logFrame(self):
        self.logFrame = ttk.LabelFrame(self)
        self.logFrame.pack(side=tk.LEFT)
        if 1:
            self.recordListboxScroll_2 = tk.Scrollbar(
                self.logFrame, orient=tk.VERTICAL)
            self.recordListboxScroll_2.grid(
                row=2, column=11, sticky="ns")
            self.recordListbox_2 = tk.Listbox(
                self.logFrame,
                font=("Arial", 12),
                height=10,
                width=40,
                yscrollcommand=self.recordListboxScroll_2.set,
            )
            self.recordListbox_2.grid(
                row=2, column=0, columnspan=11, sticky="nsew")
            self.recordListboxScroll_2.config(
                command=self.recordListbox_2.yview)
            self.recordClearBtn_2 = tk.Button(
                self.logFrame,
                text="清空测试记录",
                command=lambda: self.recordListbox_2.delete(
                    0, tk.END),
            )
            self.recordClearBtn_2.grid(
                row=3, column=1, padx=2, pady=1)

    def stepBtn_background_change(self, step_name, color):
        self.stepBtn_dict[step_name].config(background=color)

    def display_log(self, log):
        self.recordListbox_2.insert(tk.END, log)
        self.recordListbox_2.see(tk.END)

    def display_warning(self, warning):
        self.display_log(warning)
        self.recordListbox_2.itemconfig(
            'end', background='pink')


class StepManager:
    def __init__(self):

        self.States = [{'name': 'step00', 'on_enter': 'on_enter_Step00',
                        'on_exit': 'on_exit_Step00'},
                       {'name': 'step10', 'on_enter': 'on_enter_Step10',
                           'on_exit': 'on_exit_Step10'},
                       {'name': 'step20', 'on_enter': 'on_enter_Step20',
                           'on_exit': 'on_exit_Step20'},
                       {'name': 'step30', 'on_enter': 'on_enter_Step30',
                           'on_exit': 'on_exit_Step30'},
                       {'name': 'step40', 'on_enter': 'on_enter_Step40',
                           'on_exit': 'on_exit_Step40'},
                       {'name': 'step50', 'on_enter': 'on_enter_Step50',
                           'on_exit': 'on_exit_Step50'},
                       {'name': 'step60', 'on_enter': 'on_enter_Step60',
                           'on_exit': 'on_exit_Step60'},
                       {'name': 'step70', 'on_enter': 'on_enter_Step70',
                           'on_exit': 'on_exit_Step70'}
                       ]

        self.machine = Machine(model=self, states=self.States, initial='step00', ordered_transitions=True,
                               before_state_change='before_state_change', after_state_change='after_state_change')

        self._stepManagerView = None

        self.pool = ThreadPoolExecutor(max_workers=3)

    # FIXME: 通过property动态属性方式，解决wrapper中访问self.stepManagerView是None的情况
    @property
    def stepManagerView(self):
        return self._stepManagerView

    @stepManagerView.setter
    def stepManagerView(self, value):
        self._stepManagerView = value

    def decorator_wrap_change_green(self, func):
        '''
        定义装饰器，用于在执行func前后，改变stepBtn的背景颜色
        '''
        def inner():
            self.stepManagerView.stepBtn_background_change(self.state, 'green')
            func()
        return inner

    def decorator_wrap_change_gray(self, func):
        '''定义装饰器，用于在执行func前后，改变stepBtn的背景颜色'''
        def inner():
            func()
            self.stepManagerView.stepBtn_background_change(self.state, 'gray')
        return inner

    def add_default_tostate(self):
        def on_enter_default(state):
            @self.decorator_wrap_change_green
            def wrapper():
                logger.info(f'on_enter_default, name: {state['on_enter']}')
            return wrapper

        def on_exit_default(state):
            @self.decorator_wrap_change_gray
            def wrapper():
                logger.info(f'on_exit_default, name: {state['on_exit']}')
            return wrapper
        for st in self.States:
            on_enter = st.get('on_enter')
            if not getattr(self, on_enter, None):
                setattr(self, on_enter, on_enter_default(st))
            on_exit = st.get('on_exit')
            if not getattr(self, on_exit, None):
                setattr(self, on_exit, on_exit_default(st))

    def before_state_change(self):
        pass
        logger.debug(f'before_state_change, leaving state: {self.state}')

    def after_state_change(self):
        pass
        logger.debug(f'after_state_change, entering state: {self.state}')

    def on_enter_Step00(self):
        @self.decorator_wrap_change_green
        def wrapper():
            logger.info('manual Step00')
        wrapper()

    def on_enter_Step10(self):
        @self.decorator_wrap_change_green
        def wrapper():
            logger.info('manual Step10')
        wrapper()


def runner():
    pass
    mainView = tk.Tk()
    # mainView.withdraw()
    step_manger = StepManager()
    stepView = StepManagerView(mainView=mainView, stepManager=step_manger)
    for i in range(20):  # 测试日志显示，用于调试
        stepView.display_warning(f'{i}--warning')
    mainView.mainloop()


if __name__ == '__main__':
    runner()
